package com.mini.grpc.spring.autoconfigure;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.HashMap;
import java.util.Map;

/**
 * gRPC客户端配置属性
 * 
 * @author Mini-gRPC
 */
@ConfigurationProperties(prefix = "mini.grpc.client")
public class GrpcClientProperties {
    
    /**
     * 是否启用gRPC客户端
     */
    private boolean enabled = true;
    
    /**
     * 默认配置
     */
    private ClientConfig defaults = new ClientConfig();
    
    /**
     * 客户端配置映射
     * key为客户端名称，value为配置
     */
    private Map<String, ClientConfig> clients = new HashMap<>();
    
    public boolean isEnabled() {
        return enabled;
    }
    
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
    
    public ClientConfig getDefaults() {
        return defaults;
    }
    
    public void setDefaults(ClientConfig defaults) {
        this.defaults = defaults;
    }
    
    public Map<String, ClientConfig> getClients() {
        return clients;
    }
    
    public void setClients(Map<String, ClientConfig> clients) {
        this.clients = clients;
    }
    
    /**
     * 获取指定客户端的配置
     * 
     * @param clientName 客户端名称
     * @return 客户端配置
     */
    public ClientConfig getClientConfig(String clientName) {
        ClientConfig config = clients.get(clientName);
        if (config == null) {
            config = new ClientConfig();
            // 使用默认配置填充
            config.mergeFrom(defaults);
        } else {
            // 合并默认配置
            ClientConfig merged = new ClientConfig();
            merged.mergeFrom(defaults);
            merged.mergeFrom(config);
            config = merged;
        }
        return config;
    }
    
    /**
     * 客户端配置
     */
    public static class ClientConfig {
        
        /**
         * 服务器地址
         */
        private String address;
        
        /**
         * 是否启用
         */
        private boolean enabled = true;
        
        /**
         * 负载均衡策略
         */
        private String loadBalancingPolicy = "round_robin";
        
        /**
         * 连接超时时间（毫秒）
         */
        private long connectTimeoutMillis = 30000;
        
        /**
         * 调用超时时间（毫秒）
         */
        private long callTimeoutMillis = 60000;
        
        /**
         * 是否启用重试
         */
        private boolean retryEnabled = true;
        
        /**
         * 最大重试次数
         */
        private int maxRetries = 3;
        
        /**
         * 最大入站消息大小（字节）
         */
        private int maxInboundMessageSize = 4 * 1024 * 1024; // 4MB
        
        /**
         * 最大入站元数据大小（字节）
         */
        private int maxInboundMetadataSize = 8192; // 8KB
        
        /**
         * 安全配置
         */
        private Security security = new Security();
        
        /**
         * 网络配置
         */
        private Network network = new Network();
        
        public String getAddress() {
            return address;
        }
        
        public void setAddress(String address) {
            this.address = address;
        }
        
        public boolean isEnabled() {
            return enabled;
        }
        
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
        
        public String getLoadBalancingPolicy() {
            return loadBalancingPolicy;
        }
        
        public void setLoadBalancingPolicy(String loadBalancingPolicy) {
            this.loadBalancingPolicy = loadBalancingPolicy;
        }
        
        public long getConnectTimeoutMillis() {
            return connectTimeoutMillis;
        }
        
        public void setConnectTimeoutMillis(long connectTimeoutMillis) {
            this.connectTimeoutMillis = connectTimeoutMillis;
        }
        
        public long getCallTimeoutMillis() {
            return callTimeoutMillis;
        }
        
        public void setCallTimeoutMillis(long callTimeoutMillis) {
            this.callTimeoutMillis = callTimeoutMillis;
        }
        
        public boolean isRetryEnabled() {
            return retryEnabled;
        }
        
        public void setRetryEnabled(boolean retryEnabled) {
            this.retryEnabled = retryEnabled;
        }
        
        public int getMaxRetries() {
            return maxRetries;
        }
        
        public void setMaxRetries(int maxRetries) {
            this.maxRetries = maxRetries;
        }
        
        public int getMaxInboundMessageSize() {
            return maxInboundMessageSize;
        }
        
        public void setMaxInboundMessageSize(int maxInboundMessageSize) {
            this.maxInboundMessageSize = maxInboundMessageSize;
        }
        
        public int getMaxInboundMetadataSize() {
            return maxInboundMetadataSize;
        }
        
        public void setMaxInboundMetadataSize(int maxInboundMetadataSize) {
            this.maxInboundMetadataSize = maxInboundMetadataSize;
        }
        
        public Security getSecurity() {
            return security;
        }
        
        public void setSecurity(Security security) {
            this.security = security;
        }
        
        public Network getNetwork() {
            return network;
        }
        
        public void setNetwork(Network network) {
            this.network = network;
        }
        
        /**
         * 从另一个配置合并属性
         * 
         * @param other 其他配置
         */
        public void mergeFrom(ClientConfig other) {
            if (other == null) {
                return;
            }
            
            if (this.address == null && other.address != null) {
                this.address = other.address;
            }
            if (this.loadBalancingPolicy == null && other.loadBalancingPolicy != null) {
                this.loadBalancingPolicy = other.loadBalancingPolicy;
            }
            if (this.connectTimeoutMillis == 0 && other.connectTimeoutMillis > 0) {
                this.connectTimeoutMillis = other.connectTimeoutMillis;
            }
            if (this.callTimeoutMillis == 0 && other.callTimeoutMillis > 0) {
                this.callTimeoutMillis = other.callTimeoutMillis;
            }
            if (this.maxRetries == 0 && other.maxRetries > 0) {
                this.maxRetries = other.maxRetries;
            }
            if (this.maxInboundMessageSize == 0 && other.maxInboundMessageSize > 0) {
                this.maxInboundMessageSize = other.maxInboundMessageSize;
            }
            if (this.maxInboundMetadataSize == 0 && other.maxInboundMetadataSize > 0) {
                this.maxInboundMetadataSize = other.maxInboundMetadataSize;
            }
            
            // 合并嵌套配置
            if (this.security == null) {
                this.security = new Security();
            }
            this.security.mergeFrom(other.security);
            
            if (this.network == null) {
                this.network = new Network();
            }
            this.network.mergeFrom(other.network);
        }
    }
    
    /**
     * 安全配置
     */
    public static class Security {
        
        /**
         * 是否启用TLS
         */
        private boolean enabled = false;
        
        /**
         * 信任证书文件路径
         */
        private String trustCertCollectionFile;
        
        /**
         * 客户端证书文件路径
         */
        private String certChainFile;
        
        /**
         * 客户端私钥文件路径
         */
        private String privateKeyFile;
        
        /**
         * 是否跳过证书验证
         */
        private boolean insecure = false;
        
        public boolean isEnabled() {
            return enabled;
        }
        
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
        
        public String getTrustCertCollectionFile() {
            return trustCertCollectionFile;
        }
        
        public void setTrustCertCollectionFile(String trustCertCollectionFile) {
            this.trustCertCollectionFile = trustCertCollectionFile;
        }
        
        public String getCertChainFile() {
            return certChainFile;
        }
        
        public void setCertChainFile(String certChainFile) {
            this.certChainFile = certChainFile;
        }
        
        public String getPrivateKeyFile() {
            return privateKeyFile;
        }
        
        public void setPrivateKeyFile(String privateKeyFile) {
            this.privateKeyFile = privateKeyFile;
        }
        
        public boolean isInsecure() {
            return insecure;
        }
        
        public void setInsecure(boolean insecure) {
            this.insecure = insecure;
        }
        
        public void mergeFrom(Security other) {
            if (other == null) {
                return;
            }
            
            if (this.trustCertCollectionFile == null && other.trustCertCollectionFile != null) {
                this.trustCertCollectionFile = other.trustCertCollectionFile;
            }
            if (this.certChainFile == null && other.certChainFile != null) {
                this.certChainFile = other.certChainFile;
            }
            if (this.privateKeyFile == null && other.privateKeyFile != null) {
                this.privateKeyFile = other.privateKeyFile;
            }
        }
    }
    
    /**
     * 网络配置
     */
    public static class Network {
        
        /**
         * 是否启用keepalive
         */
        private boolean keepAliveEnabled = false;
        
        /**
         * keepalive时间间隔（秒）
         */
        private long keepAliveTimeSeconds = 30;
        
        /**
         * keepalive超时时间（秒）
         */
        private long keepAliveTimeoutSeconds = 5;
        
        /**
         * 是否在没有活跃流时也发送keepalive
         */
        private boolean keepAliveWithoutCalls = false;
        
        /**
         * 最大连接空闲时间（秒）
         */
        private long maxConnectionIdleSeconds = 300; // 5分钟
        
        public boolean isKeepAliveEnabled() {
            return keepAliveEnabled;
        }
        
        public void setKeepAliveEnabled(boolean keepAliveEnabled) {
            this.keepAliveEnabled = keepAliveEnabled;
        }
        
        public long getKeepAliveTimeSeconds() {
            return keepAliveTimeSeconds;
        }
        
        public void setKeepAliveTimeSeconds(long keepAliveTimeSeconds) {
            this.keepAliveTimeSeconds = keepAliveTimeSeconds;
        }
        
        public long getKeepAliveTimeoutSeconds() {
            return keepAliveTimeoutSeconds;
        }
        
        public void setKeepAliveTimeoutSeconds(long keepAliveTimeoutSeconds) {
            this.keepAliveTimeoutSeconds = keepAliveTimeoutSeconds;
        }
        
        public boolean isKeepAliveWithoutCalls() {
            return keepAliveWithoutCalls;
        }
        
        public void setKeepAliveWithoutCalls(boolean keepAliveWithoutCalls) {
            this.keepAliveWithoutCalls = keepAliveWithoutCalls;
        }
        
        public long getMaxConnectionIdleSeconds() {
            return maxConnectionIdleSeconds;
        }
        
        public void setMaxConnectionIdleSeconds(long maxConnectionIdleSeconds) {
            this.maxConnectionIdleSeconds = maxConnectionIdleSeconds;
        }
        
        public void mergeFrom(Network other) {
            if (other == null) {
                return;
            }
            
            if (this.keepAliveTimeSeconds == 0 && other.keepAliveTimeSeconds > 0) {
                this.keepAliveTimeSeconds = other.keepAliveTimeSeconds;
            }
            if (this.keepAliveTimeoutSeconds == 0 && other.keepAliveTimeoutSeconds > 0) {
                this.keepAliveTimeoutSeconds = other.keepAliveTimeoutSeconds;
            }
            if (this.maxConnectionIdleSeconds == 0 && other.maxConnectionIdleSeconds > 0) {
                this.maxConnectionIdleSeconds = other.maxConnectionIdleSeconds;
            }
        }
    }
} 